/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.actions.zip.signing;


import org.jetbrains.annotations.NotNull;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

public class ManifestDigester
{
	private final byte[] manifestBytes;
	private final Map<String, ManifestDigesterEntry> entries;

	@NotNull
	public static final String ManifestMainAttributesHeader = "Manifest-Main-Attributes";

	public ManifestDigester(final @NotNull byte[] manifestBytes)
	{
		this.manifestBytes = manifestBytes;
		entries = new HashMap<>();

		final Position localPosition = new Position();

		if (!(findSection(0, localPosition)))
		{
			return;
		}

		entries.put(ManifestMainAttributesHeader, new ManifestDigesterEntry(manifestBytes, 0, localPosition.startOfNext));

		int index = localPosition.startOfNext;
		while (findSection(index, localPosition))
		{
			int j = localPosition.endOfFirstLine - index + 1;
			int k = localPosition.endOfSection - index + 1;
			int l = localPosition.startOfNext - index;

			if ((j > 6) && (isNameAttribute(manifestBytes, index)))
			{
				final StringBuilder builder = new StringBuilder();
				try
				{
					builder.append(new String(manifestBytes, index + 6, j - 6, "UTF8"));

					int i1 = index + j;
					if (i1 - index < k)
					{
						if (manifestBytes[i1] == 13)
						{
							i1 += 2;
						}
						else
						{
							++i1;
						}
					}

					while ((i1 - index < k) && (manifestBytes[(i1++)] == 32))
					{
						int length;
						int offset = i1;

						while ((i1 - index < k) && (manifestBytes[(i1++)] != 10))
						{
							;
						}
						if (manifestBytes[(i1 - 1)] != 10)
						{
							return;
						}

						if (manifestBytes[(i1 - 2)] == 13)
						{
							length = i1 - offset - 2;
						}
						else
						{
							length = i1 - offset - 1;
						}

						builder.append(new String(manifestBytes, offset, length, "UTF8"));
					}
					entries.put(builder.toString(), new ManifestDigesterEntry(manifestBytes, index, l));
				}
				catch (UnsupportedEncodingException impossible)
				{
					throw new IllegalStateException("Java is broken", impossible);
				}
			}
			index = localPosition.startOfNext;
		}
	}

	private boolean isNameAttribute(final byte[] data, final int index)
	{
		return ((((data[index] == 78) || (data[index] == 110))) && (((data[(index + 1)] == 97) || (data[(index + 1)] == 65))) && (((data[(index + 2)] == 109) || (data[(index + 2)] == 77))) && (((data[(index + 3)] == 101) || (data[(index + 3)] == 69))) && (data[(index + 4)] == 58) && (data[(index + 5)] == 32));
	}

	private boolean findSection(final int paramInt, final @NotNull Position position)
	{
		int i = paramInt;
		int j = this.manifestBytes.length;
		int k = paramInt;

		int l = 1;

		position.endOfFirstLine = -1;

		while (i < j)
		{
			int i1 = this.manifestBytes[i];
			switch (i1)
			{
				case 13:
					if (position.endOfFirstLine == -1)
					{
						position.endOfFirstLine = (i - 1);
					}
					if ((i < j) && (this.manifestBytes[(i + 1)] == 10))
					{
						++i;
					}

				case 10:
					if (position.endOfFirstLine == -1)
					{
						position.endOfFirstLine = (i - 1);
					}
					if ((l != 0) || (i == j - 1))
					{
						if (i == j - 1)
						{
							position.endOfSection = i;
						}
						else
						{
							position.endOfSection = k;
						}
						position.startOfNext = (i + 1);
						return true;
					}

					k = i;
					l = 1;

					break;
				default:
					l = 0;
			}

			++i;
		}
		return false;
	}

	@NotNull
	public ManifestDigesterEntry get(final @NotNull String headerName)
	{
		return entries.get(headerName);
	}

	@NotNull
	public ManifestDigesterEntry manifestDigest()
	{
		return new ManifestDigesterEntry(manifestBytes, 0, manifestBytes.length);
	}

	private class Position
	{
		int endOfFirstLine = 0;
		int endOfSection = 0;
		int startOfNext = 0;
	}
}
